package com.hnec.dms.log.operation;

import java.lang.reflect.Method;

import com.hnec.dms.log.service.OpLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;

/**
 * 上传日志到S3的注解标签切面类
 *
 * @Author: liwq
 * @Author: hidebug
 */
@Component
@Aspect
public class OperationLogInterceptor {

	private static final Logger logger = LoggerFactory.getLogger(OperationLogInterceptor.class);

	@Autowired
	private OpLogService opLogService;

	/**
	 * 声明切点的作用范围
	 */
	@Pointcut("@annotation(com.hnec.dms.log.operation.OperationLog)")
	public void field() {
	}

	/**
	 * 拦截操作执行时
	 *
	 * @param pjp
	 */
	@Around("field()")
	public Object logActionInExecution(ProceedingJoinPoint pjp) throws Throwable {
		OpLogForm logForm = new OpLogForm();
		logForm.setStartTime(System.currentTimeMillis());

		// 获取实体类target及其反射等相关信息
		Object target = pjp.getTarget();
		String methodName = pjp.getSignature().getName();
		String clsName = target.getClass().getName();

		// 验证标签是否在方法上
		Signature sig = pjp.getSignature();
		MethodSignature msig = null;
		if (!(sig instanceof MethodSignature)) {
			throw new IllegalArgumentException("This annotation can only be used in methods");
		}
		msig = (MethodSignature) sig;
		Class<?>[] parameterTypes = msig.getMethod().getParameterTypes();
		Method method = target.getClass().getMethod(methodName, parameterTypes);

		OperationLog operationLog = method.getAnnotation(OperationLog.class);
		logForm.setAction(operationLog.action());
		logForm.setModule(operationLog.module());

		// 输入参数
		if (operationLog.recordInputValue()) {
			Object[] args = pjp.getArgs();
			logForm.setValueBefore(JSONObject.toJSONString(args));
		} else {
			logForm.setValueBefore(JSONObject.toJSONString("Ignore the inputed"));
		}

		// 业务方法自身异常则直接抛出对应异常
		Object object = pjp.proceed();
		if (operationLog.recordReturnValue()) {
			logForm.setValueAfter(JSONObject.toJSONString(object));
		} else {
			logForm.setValueAfter(JSONObject.toJSONString("Ignore the returned"));
		}

		logForm.setEndTime(System.currentTimeMillis());

		// 记录日志
		opLogService.logOperation(logForm);

		return object;
	}

}
